﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Learn_customEvent
{
    class Program
    {
        static void Main(string[] args)  // 完整的事件循环
        {
            Customer customer = new Customer();
            Waiter waiter = new Waiter();
            customer.Order += waiter.Action;
            customer.Action("Kongpao Chicken", "large");
            customer.PayTheBill();
        }
    }

    public class OrderEventArgs : EventArgs
    {
        public string DishName { get; set; }
        public string Size { get; set; }
    }

    // 自定义 OrderEventHandler，可以直接使用.net准备好的EventHandler
    //public delegate void OrderEventHandler(Customer customer, OrderEventArgs e);

    public class Customer  // 事件的拥有者
    {
        //private OrderEventHandler orderEventHandler;

        //public event OrderEventHandler Order  // 完整的事件定义
        //{
        //    add
        //    {
        //        this.orderEventHandler += value;
        //    }

        //    remove
        //    {
        //        this.orderEventHandler -= value;
        //    }
        //}

        public event EventHandler Order;  // 简略的事件定义
        /*
         用于声明Foo事件的委托，一般命名为 FooEventHandler（除非是一个非常通用的事件约束）
        FooEventHandler委托的参数一般有两个（由Win32 API演变而来，历史悠久）
            第一个是object类型，名字为sender，实际上就是事件的拥有者、事件的source。
            第二个是EventArgs类的派生类，类名一般为FooEventArgs，参数名为e。也就是事件参数
            虽然没有官方的说法，但我们可以把委托的参数列表看做是事件发生后发送给事件响应者的“事件消息”
        触发Foo事件的方法一般命名为OnFoo，即“因何引发”
            访问级别为protected，不能为public
         */
        
        public double Bill { get; set; }  // 这是一个自动实现的属性，若对get和set方法重写则是自定义的
        public void PayTheBill()
        {
            Console.WriteLine("I will pay ${0}.", this.Bill);
        }

        public void WalkIn()
        {
            Console.WriteLine("Walk into the restaurant.");
        }

        public void SitDown()
        {
            Console.WriteLine("Sit down.");
        }

        public void Think(string dishName, string size)
        {
            for (int i = 0; i < 5; i++)
            {
                Console.WriteLine("Let me think……");
                Thread.Sleep(1000);
            }

            //if(this.Order != null)
            //{
            //    OrderEventArgs e = new OrderEventArgs();
            //    e.DishName = "Kongpao Chicken";
            //    e.Size = "large";
            //    this.Order.Invoke(this, e);
            //}

            OnOrder(dishName, size);
        }

        protected void OnOrder(string dishName, string size)
        {
            if (this.Order != null)
            {
                OrderEventArgs e = new OrderEventArgs();
                e.DishName = dishName;
                e.Size = size;
                this.Order.Invoke(this, e);
            }
        }

        public void Action(string dishName, string size)
        {
            Console.ReadLine();
            this.WalkIn();
            this.SitDown();
            this.Think(dishName, size);
        }
    }

    public class Waiter  // 事件的响应者
    {
        //internal void Action(Customer customer, OrderEventArgs e)
        //{
        //    Console.WriteLine("I will serve you the dish - {0}", e.DishName);
        //    double price = 10;
        //    switch(e.Size)
        //    {
        //        case "small":
        //            price *= 0.5;
        //            break;
        //        case "large":
        //            price *= 1.5;
        //            break;
        //        default:
        //            break;
        //    }

        //    customer.Bill += price;
        //}
        internal void Action(object sender, EventArgs e)
        {
            Customer customer = sender as Customer;
            OrderEventArgs orderInfo = e as OrderEventArgs;
            Console.WriteLine("I will serve you the dish - {0}", orderInfo.DishName);
            double price = 10;

            switch (orderInfo.Size)
            {
                case "small":
                    price *= 0.5;
                    break;
                case "large":
                    price *= 1.5;
                    break;
                default:
                    break;
            }

            customer.Bill += price;
        }
    }
}
